using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Text;
using System.Security.Cryptography;
using System.Web;

namespace DAL
{
    /// <summary>
    /// This class managers users on the site. It has a few special methods for keeping track
    /// of users and hashing passwords.
    /// </summary>
    public class Users : DAL.DataManager<User>
    {
        #region Boilerplate Methods
        private static Users Instance = new Users();
        static Users() { }

        public override string TableName
        {
            get { return @"yboard_users"; }
        }

        public static string GetTableName()
        {
            return Instance.TableName;
        }

        protected override void CopyToItem(DataRow Row, User Item)
        {
            Item.Username = Convert.ToString(Row["Username"]);
            Item.Password = Convert.ToString(Row["Password"]);
            switch (Convert.ToInt16(Row["Status"]))
            {
                case 4:
                    Item.Status = User.UserStatus.Administrator;
                    break;
                case 3:
                    Item.Status = User.UserStatus.SuperModerator;
                    break;
                case 2:
                    Item.Status = User.UserStatus.Moderator;
                    break;
                case -1:
                    Item.Status = User.UserStatus.Banned;
                    break;
                default:
                    Item.Status = User.UserStatus.Member;
                    break;
            }

            if (Row["Email"] != System.DBNull.Value)
            {
                Item.EmailAddress = Row["Email"].ToString();
            }
            else
            {
                Item.EmailAddress = null;
            }

            Item.RegistrationDate = Convert.ToDateTime(Row["RegistrationDate"]);
            Item.LastActivityDate = Convert.ToDateTime(Row["LastActivityDate"]);
            Item.AdminSettings.AllowSignature = Convert.ToBoolean(Row["AllowSignature"]);

            if (Row["Signature"] != System.DBNull.Value)
            {
                Item.Signature = Row["Signature"].ToString();
            }
            else
            {
                Item.Signature = null;
            }

            Item.TotalPosts = Convert.ToInt32(Row["TotalPosts"]);
            Item.TotalThreads = Convert.ToInt32(Row["TotalThreads"]);

            Item.UserSettings.ShowUserSignatures = Convert.ToBoolean(Row["ShowUserSignatures"]);
            Item.AdminSettings.AllowAvatar = Convert.ToBoolean(Row["AllowAvatar"]);

            if (Row["AvatarExtension"] != System.DBNull.Value)
            {
                Item.AvatarExtension = Row["AvatarExtension"].ToString();
            }
            else
            {
                Item.AvatarExtension = null;
            }

            Item.UserSettings.ShowUserAvatars = Convert.ToBoolean(Row["ShowUserAvatars"]);

            if (Row["Location"] != System.DBNull.Value)
            {
                Item.Location = Row["Location"].ToString();
            }
            else
            {
                Item.Location = null;
            }

            if (Row["Interests"] != System.DBNull.Value)
            {
                Item.Interests = Row["Interests"].ToString();
            }
            else
            {
                Item.Interests = null;
            }

            if (Row["Bio"] != System.DBNull.Value)
            {
                Item.Bio = Row["Bio"].ToString();
            }
            else
            {
                Item.Bio = null;
            }

            Item.FateSealer = Convert.ToInt32(Row["FateSealer"]);
            Item.AdminSettings.AllowUserTitle = Convert.ToBoolean(Row["AllowUserTitle"]);

            if (Row["UserTitle"] != System.DBNull.Value)
            {
                Item.UserTitle = Row["UserTitle"].ToString();
            }
            else
            {
                Item.UserTitle = null;
            }

            Item.UserSettings.DateTimeOffset = Convert.ToInt32(Row["DateTimeOffset"]);

            if (Row["Website"] != System.DBNull.Value)
            {
                Item.Website = Row["Website"].ToString();
            }
            else
            {
                Item.Website = null;
            }

            if (Row["Occupation"] != System.DBNull.Value)
            {
                Item.Occupation = Row["Occupation"].ToString();
            }
            else
            {
                Item.Occupation = null;
            }

            Item.AdminSettings.AllowPublicAdmin = Convert.ToBoolean(Row["AllowPublicAdmin"]);
        }

        protected override void CopyFromItem(DataManagerQuery query, User Item)
        {
            query.AddParam("Username", Item.Username);
            query.AddParam("Password", Item.Password);
            switch (Item.Status)
            {
                case User.UserStatus.Administrator:
                    query.AddParam("Status", 4);
                    break;
                case User.UserStatus.SuperModerator:
                    query.AddParam("Status", 3);
                    break;
                case User.UserStatus.Moderator:
                    query.AddParam("Status", 2);
                    break;
                case User.UserStatus.Banned:
                    query.AddParam("Status", -1);
                    break;
                default:
                    query.AddParam("Status", 1);
                    break;
            }

            query.AddParam("Email", Item.EmailAddress);
            query.AddParam("RegistrationDate", Item.RegistrationDate);
            query.AddParam("LastActivityDate", Item.LastActivityDate);
            query.AddParam("AllowSignature", Item.AdminSettings.AllowSignature);
            query.AddParam("Signature", Item.Signature);
            query.AddParam("TotalPosts", Item.TotalPosts);
            query.AddParam("TotalThreads", Item.TotalThreads);
            query.AddParam("ShowUserSignatures", Item.UserSettings.ShowUserSignatures);
            query.AddParam("AllowAvatar", Item.AdminSettings.AllowAvatar);
            query.AddParam("AvatarExtension", Item.AvatarExtension);
            query.AddParam("ShowUserAvatars", Item.UserSettings.ShowUserSignatures);
            query.AddParam("Location", Item.Location);
            query.AddParam("Interests", Item.Interests);
            query.AddParam("Bio", Item.Bio);
            query.AddParam("Fatesealer", Item.FateSealer);
            query.AddParam("AllowUserTitle", Item.AdminSettings.AllowUserTitle);
            query.AddParam("Usertitle", Item.UserTitle);
            query.AddParam("DateTimeOffset", Item.UserSettings.DateTimeOffset);
            query.AddParam("Website", Item.Website);
            query.AddParam("Occupation", Item.Occupation);
            query.AddParam("AllowPublicAdmin", Item.AdminSettings.AllowPublicAdmin);
        }
        #endregion

        public static User Item(Int64 id)
        {
            return Instance.GetItem(id);
        }

        public static List<User> All()
        {
            return Instance.GetItems();
        }

        /// <summary>
        /// Adds a new user to the database.
        /// </summary>
        /// <param name="Item">A User object that you want to add to the database.</param>
        /// <param name="plaintextPassword">The unencrypted password. This password will be 
        /// MD5-hashed before being committed to the database.</param>
        public static void Add(User Item, string cleartextPassword)
        {
            Item.Password = Helpers.CryptoHelper.MD5(cleartextPassword);

            Item.UserSettings.ShowUserAvatars = true;
            Item.UserSettings.ShowUserSignatures = true;
            Item.AdminSettings.AllowAvatar = true;
            Item.AdminSettings.AllowSignature = true;
            Item.AdminSettings.AllowUserTitle = true;
            Item.AdminSettings.AllowPublicAdmin = true;
            
            Item.RegistrationDate = DateTime.Now;
            Item.LastActivityDate = DateTime.Now;
            Instance.Insert(Item);
            //CurrentUser = Item;
            Managers.UserLoginManager.CurrentUser = Item;
            if (Managers.UserLoginManager.BannedCookie == true)
            {
                BanUser(Item);
            }
        }

        public static void Save(User Item)
        {
            Instance.Update(Item);
        }

        /// <summary>
        /// This function will change a User's password.
        /// </summary>
        /// <param name="Item">The User that you want to update.</param>
        /// <param name="plaintextPassword">The new password of the user in plaintext.</param>
        public static void ChangePassword(User Item, string cleartextPassword)
        {
            Item.Password = Helpers.CryptoHelper.MD5(cleartextPassword);
            Save(Item);


            // updating cookies
            Managers.UserLoginManager.UserPasswordCookie = Item.Password;
        }

        public static User GetByUserIdAndPassword(Int64 userID, string hashedPassword)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("ID", userID);
            query.AddParam("password", hashedPassword);

            List<User> myUsers = Instance.GetItems(query);
            if (myUsers.Count > 0)
            {
                return myUsers[0];
            }
            else
            {
                return null;
            }
        }

        public static User GetByUsernameAndPassword(string username, string hashedpassword)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("username", username);
            query.AddParam("password", hashedpassword);

            List<User> myUsers = Instance.GetItems(query);
            if (myUsers.Count > 0)
            {
                return myUsers[0];
            }
            else
            {
                return null;
            }
        }

        public static User GetByUsername(string username)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("username", username);

            List<User> myUsers = Instance.GetItems(query);
            if (myUsers.Count > 0)
            {
                return myUsers[0];
            }
            else
            {
                return null;
            }
        }

        public static List<User> GetByUsernameLike(string partialUsername)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("username", Comparison.Like, partialUsername);
            query.AddSort("username", Sort.Asc);
            return Instance.GetItems(query);
        }

        public static List<User> GetActiveUsers()
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddParam("LastActivityDate", Comparison.GreaterThanOrEqual, DateTime.Now.AddMinutes(-15));
            query.AddParam("Status", Comparison.GreaterThanOrEqual, 0);
            query.AddSort("username", Sort.Asc);
            return Instance.GetItems(query);
        }

        public static int GetTotalUsers()
        {
            return Instance.GetCount();
        }

        public static DataManagerPage<User> GetAllUsersByPage(int page)
        {
            DataManagerQuery query = new DataManagerQuery();
            query.AddSort("Username", Sort.Asc);
            return Instance.GetItemsByPage(query, page, 25);
        }

        public static void BanUser(User user)
        {
            RemoveUserPermissions(user);
            Save(user);
        }

        private static void RemoveUserPermissions(User Item)
        {
            Item.Status = DAL.User.UserStatus.Banned;
            //Item.AdminSettings.AllowAvatar = false;
            Item.AdminSettings.AllowPublicAdmin = false;
            //Item.AdminSettings.AllowSignature = false;
            //Item.AdminSettings.AllowUserTitle = false;
        }

        public static void AnnihilateSpammer(User Item)
        {
            RemoveAllThreadsAndPostsByUser(Item);
            BanUser(Item);
        }

        public static void RemoveAllThreadsAndPostsByUser(User user)
        {
            StringBuilder sb = new StringBuilder();
            // deleting all threads by user
            sb.AppendLine("UPDATE t SET Status = -1");
            sb.AppendLine("FROM [threads] t");
            sb.AppendLine("INNER JOIN [posts] p on p.ID = t.FirstPostID");
            sb.AppendLine("WHERE p.UserID = @userID;");
            // deleting all posts by user
            sb.AppendLine("UPDATE [posts] SET Visible = 0 WHERE UserID = @userID;");
            // reseting number of replies for all threads
            sb.AppendLine("UPDATE [threads] SET TotalReplies = UpdatedReplies.PostCount");
            sb.AppendLine("FROM [threads]");
            sb.AppendLine("INNER JOIN");
            sb.AppendLine("     (");
            sb.AppendLine("         SELECT ThreadID, (Count(*) - 1) as PostCount");
            sb.AppendLine("         FROM [posts]");
            sb.AppendLine("         WHERE Visible = 1");
            sb.AppendLine("         GROUP BY ThreadID");
            sb.AppendLine("     ) as UpdatedReplies");
            sb.AppendLine("     ON UpdatedReplies.ThreadID = [threads].ID");


            string sql = sb.ToString();
            sql = sql.Replace("[threads]", Threads.GetTableName());
            sql = sql.Replace("[posts]", Posts.GetTableName());

            System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand(sql);
            comm.Parameters.AddWithValue("@userID", user.ID);

            Instance.ExecuteNonQuery(comm);

            //Threads.Pool.Clear();
            //Posts.Pool.Clear();
        }
    }

    public class User : DAL.DataManagerRow
    {
        public enum UserStatus
        {
            Member = 1,
            Moderator = 2,
            SuperModerator = 3,
            Administrator = 4,
            Unregistered = 0,
            Banned = -1
        }

        private string _Username;
        public string Username
        {
            get
            {
                return _Username;
            }
            set
            {
                _Username = value;
            }
        }

        private string _Password;
        public string Password
        {
            get
            {
                return _Password;
            }
            set
            {
                _Password = value;
            }
        }

        private UserStatus _status;
        public UserStatus Status
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
            }
        }

        private string _emailAddress;
        public string EmailAddress
        {
            get
            {
                return _emailAddress;
            }
            set
            {
                _emailAddress = value;
            }
        }

        private DateTime _registrationDate;
        public DateTime RegistrationDate
        {
            get
            {
                return _registrationDate;
            }
            set
            {
                _registrationDate = value;
            }
        }

        private DateTime _lastActivityDate;
        public DateTime LastActivityDate
        {
            get
            {
                return _lastActivityDate;
            }
            set
            {
                _lastActivityDate = value;
            }
        }

        private string _signature;
        public string Signature
        {
            get
            {
                return _signature;
            }
            set
            {
                _signature = value;
            }
        }

        private int _totalPosts;
        public int TotalPosts
        {
            get
            {
                return _totalPosts;
            }
            set
            {
                _totalPosts = value;
            }
        }

        private int _totalThreads;
        public int TotalThreads
        {
            get
            {
                return _totalThreads;
            }
            set
            {
                _totalThreads = value;
            }
        }

        private string _avatarExtension;
        public string AvatarExtension
        {
            get
            {
                return _avatarExtension;
            }
            set
            {
                _avatarExtension = value;
            }
        }

        private string _location;
        public string Location
        {
            get
            {
                return _location;
            }
            set
            {
                _location = value;
            }
        }

        private string _interests;
        public string Interests
        {
            get
            {
                return _interests;
            }
            set
            {
                _interests = value;
            }
        }

        private string _bio;
        public string Bio
        {
            get
            {
                return _bio;
            }
            set
            {
                _bio = value;
            }
        }

        private int _fateSealer;
        public int FateSealer
        {
            get
            {
                return _fateSealer;
            }
            set
            {
                _fateSealer = value;
            }
        }

        private string _userTitle;
        public string UserTitle
        {
            get
            {
                return _userTitle;
            }
            set
            {
                _userTitle = value;
            }
        }

        private string _Website;
        public string Website
        {
            get
            {
                return _Website;
            }
            set
            {
                _Website = value;
            }
        }

        private string _Occupation;
        public string Occupation
        {
            get
            {
                return _Occupation;
            }
            set
            {
                _Occupation = value;
            }
        }

        private UserSettings _UserSettings;
        public UserSettings UserSettings
        {
            get
            {
                if (_UserSettings == null)
                {
                    _UserSettings = new UserSettings();
                }
                return _UserSettings;
            }
        }

        private AdminUserSettings _AdminSettings;
        public AdminUserSettings AdminSettings
        {
            get
            {
                if (_AdminSettings == null)
                {
                    _AdminSettings = new AdminUserSettings();
                }
                return _AdminSettings;
            }
        }

        public bool HasAvatar
        {
            get
            {
                return !String.IsNullOrEmpty(AvatarExtension);
            }
        }

        public bool HasUserTitle
        {
            get
            {
                return !String.IsNullOrEmpty(UserTitle);
            }
        }
        public bool HasSignature
        {
            get
            {
                return !String.IsNullOrEmpty(Signature);
            }
        }

        public bool HasPermissions(UserStatus minimalPermissions)
        {
            return (Status >= minimalPermissions);
        }
    }

    public class UserSettings
    {
        private bool _showUserSignatures;
        public bool ShowUserSignatures
        {
            get
            {
                return _showUserSignatures;
            }
            set
            {
                _showUserSignatures = value;
            }
        }

        private bool _showUserAvatars;
        public bool ShowUserAvatars
        {
            get
            {
                return _showUserAvatars;
            }
            set
            {
                _showUserAvatars = value;
            }
        }

        private int _DateTimeOffset;
        public int DateTimeOffset
        {
            get
            {
                return _DateTimeOffset;
            }
            set
            {
                _DateTimeOffset = value;
            }
        }
    }

    public class AdminUserSettings
    {
        private bool _allowUserTitle;
        public bool AllowUserTitle
        {
            get
            {
                return _allowUserTitle;
            }
            set
            {
                _allowUserTitle = value;
            }
        }

        private bool _allowAvatar;
        public bool AllowAvatar
        {
            get
            {
                return _allowAvatar;
            }
            set
            {
                _allowAvatar = value;
            }
        }

        private bool _allowSignature;
        public bool AllowSignature
        {
            get
            {
                return _allowSignature;
            }
            set
            {
                _allowSignature = value;
            }
        }

        private bool _allowPublicAdmin;
        public bool AllowPublicAdmin
        {
            get
            {
                return _allowPublicAdmin;
            }
            set
            {
                _allowPublicAdmin = value;
            }
        }
    }
}